2024-12-02

December Adventure

I am (trying to) do the December Adventure thing. Not sure yet how much time I will be able to allocate to this but we'll see.

Day 1

Ok, let's start with my plans for this Month.

The last three months I have been low-key writing drawing code I intend to use in certain future projects. I was mostly interested in rendering blocks that are similar in looks to those of window maker, an old X11 desktop which was a more-or-less faithful copy of the NeXTStep desktop. I am not entirely onboard with that kind of window management, but I like the aesthetic of the UI, so I wanted to copy that.

demo-1.webp

I was not trying to recreate them pixel-per-pixel perfectly, just capture the style. The code is reasonably modular. It can render various "fills" inside a "border". It can approximate the window-maker style within reason, but also the Common Desktop Environment one.

My major plan for this month is putting that code into a library I can use in my other projects. I also have some code I commonly copy-paste between projects - like a Wayland shm buffer pool or some signal handlers - that should probably also find a place in that library. The library would be some kind of proto-toolkit to create simple Wayland clients. I'll have to think about what I should name it…

I would also really like the drawing code to support double-bezel borders (right now it can only do single-bezel borders). Perhaps even make it possible to draw only parts of the border, which would be neat for desktop widgets that are stuck against a screen border. A parser for a theme configuration file would also be very useful, so that a project using the library does not have to do that itself and so that all my programs have a common file to configure their themeing (maybe even supporting realtime theme chages).

My secondary plan is to update some of my existing projects to use that library. Hopefully that will also improve the looks of some of them.

My tertiary plan is to convert my website to org-mode. I am not happy with how maintainable my current website script is and I suspect that would be an upgrade. I already have a prototype, I just need to write some eLisp to auto-generate the chronological blog index and then port my current projects. There are some issues; org-mode can not represent all the formatting I use on this website, but custom blocks and inline HTML will be a reasonable workaround. There will be minor updates to the websites formatting - and I'll be getting a sitemap as well as a keyword index for free! - but overall the structure, looks and feels of my website will not change.

Maybe I'll also do some other things, those will be shared here as well, maybe.

Now, what did I actually do today? Nothing. I was invited by a friend to bake cookies and for any reasonable person that always takes precedence.

Day 2

Today was a boring day project-wise. I spent a lot of time in uni correcting reports for the lab course I tutor, so all I had time for today was finding out how to create a dynamic C library. I did this once before, but with a different build system (meson, currently I prefer make), so I read a fair amount of documentation and created a first proof of concept. I hope to add the first "real" code to it tomorrow.

Day 15

dark.webp

Light rain hits the window of the bus. It is dark outside and the colours of the city blend and blur on the rain smudged glas. In my ears music to match the mood.

I would like to stay here for a while. But eventually I reach my destination and get out.

I skipped a few days. The things I needed to do for uni piled up and my social life got in the way again. But today I got back into it, at least partially.

I wanted something fairly simple, where I didn't need to think too much, so I worked on my website again. Barely any changes to the compile.el script, merely re-defining the function for emitting center blocks. For some reason the default one emits a <div> with the org-center class; I changed it to emit a simple <center> element.

I also cleaned up the style sheet. Lots of elements had special cases for rare (or even singular) situations. I removed those and instead introduced special elements for those special situations.

An example of those special situations is the vertical alignment of info-boxen - such as this one - and text when they are placed next to each other - like this. Only the writing index page needs a different style, so it gets a special element.

As a bonus of the simplified elements, I have to use less inline HTML.

#+begin_info-box
#+begin_side-by-side
For example, this is how I can create an info box with an image
side-by-side with text!

#+attr_html: :width 100%
[[./picture.ping]]
#+end_side-by-side
#+end_info-box

I am writing this update in my new website repo. The old one is currently still up; You'll see this article once I finished a few more minor details, like the nav-section or improving orgs default HTML output. For some reason it spams <div>'s a lot. But for semantic HTML reasons I would love to add <section> elements.

Maybe I'll also bring back the "Next" and "Previously" links I used to have at the bottom, but I am not sure they add much. When reading other peoples websites, I like those the most, on which I can get lost. Mine never achieved that quite yet, perhaps because I keep the navigation a bit to easy, perhaps because I sort the content to well (or not well enough? More subsections?). Not having those two navigation links does a small part in making my website more cozy, maybe. And it's code that is probably tedious to write…

Day 16

Isn't it technically still Day 15 if I am doing this at 00:40 and haven't slept yet? Anyway…

I worked on the org export functionality again. As I have mentioned before, I was unhappy with the default HTML output. It litters a bunch of <div>'s everywhere - which break FireFox's reader mode and aren't very semantic, let alone useful - and the IDs it generated for the clickable headlines were neither predictable nor stable - they were effectively random strings.

I fixed that by defining even more translate functions for my derived HTML export backend. Right now I have functions for template, center-block, section and headline.

Speaking of FireFox's reader mode, I also made sure the <article> element contains only (what I consider to be) the main content of the page. This helps reader mode hide all the things a user may not wish to see, like the "Articles from blogs I read"-thing at the end. I did something similar a few months back were I ensures that certain elements are hidden when the site is printed. Being accommodating to your readers is just a nice thing to do.

Day 23

I am a bit tired of working on my website, which is kinda boring. Hence me not doing a lot the last few days. At least not enough each day that I feel like sitting down and writing about it. I mainly finished the navigation section and added a comment mailto link to it. I will probably skip improving the footnotes styling for now, since that would require rewriting the inner-template export function, which would be a pain, and because I don't actually use footnotes anymore as they don't fit this medium very well in my opinion.

I also pushed some minor patches for some of my projects, but they were beither on my december adventure agenda nor were they particularly noteworthy.

I hope I can get to more interesting things soon. Seems like rivers window management protocol is a tiny bit closer every day and I want to play around with that.

Day 24

Today I discovered that my wondeful little bespoke abstraction I created for my library wrapping river's upcoming window management protocol - funneling all the various events into a neat next_event() function - isn't actually all that great. I came up with it a few weeks ago in france at a physics conference. The intent of the library is to be wrapped by other languages, so you can write a window manager for river in Scheme (everything else would be silly). Back then I was very convinced this was the correct approach to make writing bindings the most painless. Now I honestly have no idea why I thought that. Instead I just converted the library to using pointers to callback functions. Immediately the code got nicer and adding new events got simpler.

Anyway, since the rwm branch is a bit farther along now, I managed to connect to the server, sync and set-up the window management global! I even got new-window events! And I am reasonably sure the approch I am currently using is the most sound for writing a library and a reasonably featured window manager on top of that.

I decided to re-use the name of my very first C project, which was a window manager for X11: antares. (It's the name of a star). To keep things healthily confusing, that will be the name of the C library, the guile Scheme library wraping the C library and of the reference window manager written using the guile library, which probably will end up featurefull enough to challange the "reference" description.

Day 25

demo-2.webp

It's still early, but I just managed to position some windows using my guile Scheme window manager library thing. River is still a bit crashy, and I have exposed about 0.05 times the theoretically avaiable functionality in the library, but that is already enough that one could replicate rivers current default window layout and probably also the tag system.

I am still not quite sure how much functionality the library will include over just exposing the raw events and requests. At the very least, I'll probably abstract away the river-node-v1 objects.

One thing that annoyed me though is that guiles define-wrapped-pointer-type creates a record rather than a GOOPS object. That means I can't use methods. Since methods have dynamic dispatch, I'd be comfortable calling them things like f.e. set-geometry. But functions are not dispatched that way, so to avoid conflicts, I'll have to use longer names, f.e. antares-window-set-geometry.

I could wrap the record in a GOOPS object, but that's not very clean. I could maybe also skip the record and wrap the foreign pointer in directly in a GOOPS object, but I am not sure if that is a good idea…

Day 26

Behold the longest scheme macro I have written in my life so far.

(define-syntax define-binding
  (syntax-rules ()
    ((_ scheme-name (scheme-args ...)
        foreign-name (foreign-args ...)
        (assertions ...)
        (args ...))
     (define scheme-name
       (let ((foreign-function (foreign-library-function
                                antares foreign-name #:arg-types (list foreign-args ...))))
         (lambda (scheme-args ...)
           assertions ...
           (foreign-function args ...)))))))

It allows me to easiely create a scheme function wrapping a C function.

(define-binding
  antares-window-set-visibility (window visibility)
  "antares_window_set_visibility" ('* int)
  ((assert (antares-window? window))
   (assert (boolean? visibility)))
  ((unwrap-antares-window window)
   (if visibility 1 0)))

By the way, if you ever want to debug a macro in guile, you can type ,expand (expression ...) in the REPL to see what the expression expands to. Super useful.

Day 27

Added most of the remaining window events and some quality of life for library users (returning error values rather than crashing).

Somewhere is still a bug that triggers an "illegal instruction" crash. I really hope my code causes that, because otherwise this smells like the automagic codegen of guiles FFI doing something funky, which I can't do anything about.

What's missing now to actually get to a state where I can write a useful window manager is to expose the window requests and to implement seats. Eventually I'll also want to do custom border and desktop widget rendering, but only after the window management bits are there and stable and useful.

Day 28

Lot's of crashes in both river and antares. I have reported the river crashes, but the antares crashes are weird. It's not the library itself, I tested that. It must be somewhere in the guile library or guile itself. Sometimes it even is a SIGILL, which is worrying.

Fun fact: Asan, valgrind and gdb are all useless when you try to debug issues across FFI borders!

AddressSanitizer:DEADLYSIGNAL
=================================================================
==64087==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x7918c3b01052 bp 0x7fffb3b4d250 sp 0x7fffb3b4d218 T0)
==64087==The signal is caused by a READ memory access.
==64087==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
    #0 0x7918c3b01052  (<unknown module>)
    #1 0x7918c56fb595  (/usr/lib/libffi.so.8+0x7595) (BuildId: eecfa567f01d70c2ca4b60a1f7931e5634e41eea)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (<unknown module>)
==64087==ABORTING
(gdb) bt
#0  0x00007532e2e050c0 in ?? () from /usr/lib/libguile-3.0.so.1
#1  0x00007532e2e05391 in scm_call_n () from /usr/lib/libguile-3.0.so.1
#2  0x00007532e2d7de63 in ?? () from /usr/lib/libguile-3.0.so.1
#3  0x00007532e2acb152 in ffi_closure_unix64_inner (cif=<optimized out>, fun=<optimized out>, user_data=<optimized out>, rvalue=<optimized out>, reg_args=<optimized out>,
    argp=0x7fff9a2d42f0 "`D-\232\377\177") at ../src/x86/ffi64.c:899
#4  0x00007532e2acb7b8 in ffi_closure_unix64 () at ../src/x86/unix64.S:303
#5  0x00007532dcc1d475 in ?? () from lib/antares.so
#6  0x00007fff9a2d4460 in ?? ()
#7  0x00000f5000000045 in ?? ()
#8  0x00006547ea6c6b50 in ?? ()
#9  0x00006547ea6c2790 in ?? ()
#10 0x00006547ea6c2790 in ?? ()
#11 0x00006547ea6c2790 in ?? ()
#12 0x00007fff9a2d4330 in ?? ()
#13 0x00007532e2acb596 in ffi_call_unix64 () at ../src/x86/unix64.S:104
#14 0x0000000000000000 in ?? ()

(I'll spare you valgrinds output because it says even less while being more verbose.)

Anyway, I've asked for debugging tips in the relevant channels and until I get a response will go over my code again to see if I maybe missed something…

A shame really, because I was just getting into writing some actual window management logic and doing that in scheme felt great!


Ok it's a few hours later now and I've got it: The garbage collector lost track of the callback functions and sweeped them. Defining them as toplevel variables rather than inline lambdas fixed the issue.

demo-3.webp

And now I have connected a REPL to a running instance of the window manager! Once this is actually usable, it will be insanely cool.

Articles from blogs I read (generated by openring)

whippet lab notebook: guile, heuristics, and heap growth

Greets all! Another brief note today. I have gotten Guile working with one of the Nofl-based collectors, specifically the one that scans all edges conservatively (heap-conservative-mmc / heap-conservative-parallel-mmc). Hurrah!It was a pleasant surprise h…

wingolog, May 22, 2025

Status update, May 2025

Hi! Today wlroots 0.19.0 has finally been released! Among the newly supported protocols, color-management-v1 lays the first stone of HDR support (backend and renderer bits are still being reviewed) and ext-image-copy-capture-v1 enhances the previous screen ca…

emersion, May 15, 2025

Summary of changes for April 2025

Hey everyone!This is the list of all the changes we've done to our projects during the month of April. 100r.co, updated water, ditch bag, woodstove installation, and added new photos and information on first-aid kit. Rabbit Waves, updated Triangular…

Hundred Rabbits, April 30, 2025